package problems;

import java.util.ArrayList;
import java.util.List;

import lib.MathLib;
import lib.PermutationsWithRepetition;

public class Euler051 extends AbstractEuler {

	@Override
	public Number calculate() {
		int maxPrimesFound = 6;
		int maxPrimesFoundFor = 13;
		for (int length = 2; length < 7; length++) {
			List<String> patterns = new PermutationsWithRepetition("0123456789x", length).getVariations();
			for (String pattern : patterns) {
				List<Integer> primes = getPrimes(pattern, maxPrimesFound);
				
				//we are assuming that "the first with {9,10}" don't occur before "the first with 8"
				if 	(primes.size() > maxPrimesFound ||
					(primes.size() == maxPrimesFound && primes.get(0) < maxPrimesFoundFor))
				{
					maxPrimesFound = primes.size();
					maxPrimesFoundFor = primes.get(0);
//					System.out.println("better pattern " + pattern + ": " + maxPrimesFound + " starting with " + maxPrimesFoundFor);
				}
			}

		}
		return maxPrimesFoundFor;
	}
	
	private List<Integer> getPrimes(String pattern, int minimumHits) {
		List<Integer> returnList = new ArrayList<Integer>();
		if (pattern.charAt(0) == '0') return returnList; //first char is zero -> this is a duplicate of a shorter pattern
		if (pattern.charAt(pattern.length() - 1) == '2') return returnList; //last char is two -> no combinations can be prime
		if (!pattern.contains("x")) return returnList;
		int misses = 0;
		for (int i = 0; i <= 9; i++) {
			if (i == 0 && pattern.charAt(0) == 'x') continue;
			Integer composite = new Integer(pattern.replaceAll("x", Integer.toString(i)));
			if (MathLib.isPrime(composite)) {
				returnList.add(composite);
			} else if (minimumHits > 5) {
				misses++;
				if (misses > 10 - minimumHits) return returnList;
			}
		}
		return returnList;
	}

	/**
	 * The cases given in the original problem
	 */
	public void testCountPrimes() {
		List<Integer> firstWithSix = getPrimes("x3", 6);
		assertEquals(6, firstWithSix.size());
		assertEquals(13, firstWithSix.get(0).longValue());
		
		List<Integer> firstWithSeven = getPrimes("56xx3", 7);
		assertEquals(7, firstWithSeven.size());
		assertEquals(56003, firstWithSeven.get(0).longValue());
		
	}

	@Override
	protected Number getCorrectAnswer() {
		return 121313;
	}

}
